package org.pf
{
	/**
	 * @author zeksa'
	 */
	
	import com.demonsters.debugger.MonsterDebugger;
	import flash.display.Stage;
	import flash.events.Event;
	import org.pf.base.pfBlocks.PFCleaner;
	import org.pf.base.pfBlocks.PFUpdater;
	import org.pf.base.pfSystem.PFSystemCache;
	import org.pf.base.pfSystem.PFSystemPool;
	import org.pf.constructor.PFConstructor;
	import org.pf.interfaces.IPFCache;
	import org.pf.interfaces.IPFCleaner;
	import org.pf.interfaces.IPFConstructor;
	import org.pf.interfaces.IPFPrince;
	import org.pf.interfaces.IPFState;
	import org.pf.interfaces.IPFSystemCache;
	import org.pf.interfaces.IPFSystemPool;
	import org.pf.interfaces.IPFUpdater;
	
	public class PFPrince implements IPFPrince
	{
		protected static var princeInstance:IPFPrince;
		
		private var _systemPool:IPFSystemPool;
		private var _systemCache:IPFSystemCache;
		private var _cleaner:IPFCleaner;
		private var _updater:IPFUpdater;
		private var _constructor:IPFConstructor;
		
		/**
		 * Constructor of PFPrince class.
		 * Initializes system pool object
		 */
		public function PFPrince()
		{
			_systemPool = new PFSystemPool();
			_systemPool.init();
		}
		
		/**
		 * Function returns interface to PFPrince object if it exists,
		 * if not - create and return a new one.
		 * @return IPFPrince instance interface
		 */
		public static function getPrince():IPFPrince
		{
			if (princeInstance == null)
			{
				princeInstance = new PFPrince();
			}
			return princeInstance;
		}
		
		/**
		 * @inheritDoc
		 */
		public function startup(stage:Stage, gWidth:int, gHeight:int):void
		{
			_systemCache = new PFSystemCache(stage, gWidth, gHeight);
			_systemCache.initLayers();
			
			_cleaner = new PFCleaner();
			_updater = new PFUpdater();
			_constructor = new PFConstructor();
		}
		
		/**
		 * @inheritDoc
		 */
		public function changeState():void
		{
			var t_count:Number
			_updater.stop();
			var func:Function = function(e:Event):void
			{
				_systemCache.stage.removeEventListener(Event.ENTER_FRAME, func);
				
				t_count = _systemCache.currentWorld.GetBodyCount();
				MonsterDebugger.trace("BodyCount before clean",t_count);
				if (_systemCache.currentState && _systemCache.currentCache)
				{
					_systemCache.currentState.deactivate();
					_systemCache.currentCache.deactivate();
				}
				_cleaner.clearEnviroment();
				
				t_count = _systemCache.currentWorld.GetBodyCount();
				MonsterDebugger.trace("BodyCount after clean",t_count);
				registerCache(_systemCache.nextCache);
				registerState(_systemCache.nextState);
				
				_updater.start();
			}
			_systemCache.stage.addEventListener(Event.ENTER_FRAME, func);
		
		}
		
		/**
		 * @inheritDoc
		 */
		
		public function get_SystemCache():IPFSystemCache
		{
			return _systemCache;
		}
		
		/**
		 * @inheritDoc
		 */
		public function get_SystemPool():IPFSystemPool
		{
			return _systemPool;
		}
		
		/**
		 * @inheritDoc
		 */
		public function get_Cleaner():IPFCleaner
		{
			return _cleaner;
		}
		
		/**
		 * @inheritDoc
		 */
		public function get_Updater():IPFUpdater
		{
			return _updater;
		}
		
		/**
		 * @inheritDoc
		 */
		public function get_Constructor():IPFConstructor
		{
			return _constructor;
		}
		
		/**
		 * Function registers and activates PFCache object in
		 * the system. From now this cache object starts it's work.
		 * @param	CacheClass Class of cache object you want to register.
		 */
		private function registerCache(CacheClass:Class):void
		{
			var cache:IPFCache = new CacheClass();
			_systemCache.currentCache = cache;
			cache.activate();
		}
		
		/**
		 * Function unregisters and deactivates PFCache object in
		 * the system. From now current cache object ends it's work.
		 */
		private function unregisterCache():void
		{
			_systemCache.currentCache.deactivate();
		}
		
		/**
		 * Function registers and activates PFState object in
		 * the system. From now this state object starts it's work.
		 * Next you can add some controllers to this state.
		 * @param	StateClass Class of state object you want to register.
		 */
		private function registerState(StateClass:Class):void
		{
			var state:IPFState = new StateClass();
			_systemCache.currentState = state;
			state.activate();
		}
	
	}

}